﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using NymphsLib.CommonUtilities.Extensions;
using MovieBrowser.Controller;
using MovieBrowser.Event;
using MovieBrowser.Model;
using MovieBrowser.Presentation.Events;
using MovieBrowser.Util;
using NavigateEventArgs = MovieBrowser.Event.NavigateEventArgs;

namespace MovieBrowser.Presentation.Viewer
{
    public partial class ImdbInfo : UserControl, IDebugLogEvent, IWebNavigateEvent, ISearchMovieEvent, IMovieUpdateEvent
    {
        private class SimpleKey
        {
            public long ItemId { get; set; }
            public long MovieId { get; set; }
        }
        private class SimpleActor
        {
            public long Id { get; set; }
            public Person Person { get; set; }
            public string CharacterId { get; set; }
            public string CharacterName { get; set; }
            public DateTime? Birthday { get; set; }
        }
        private class SimpleWriter
        {
            public long Id { get; set; }
            public Person Person { get; set; }
        }

        public MovieBrowserController Controller { get; set; }
        public event EventHandler DebugText;
        public void InvokeOnDebugText(Exception exception)
        {
            var handler = DebugText;
            if (handler != null) handler(this, new DebugTextEventArgs(exception));
        }
        public void InvokeOnDebugText(string text)
        {
            var handler = DebugText;
            if (handler != null) handler(this, new DebugTextEventArgs(new Exception(text)));
        }


        public event EventHandler MovieSearch;
        public void InvokeOnMovieSearchCriteriaClick(CriteriaSearchEventArgs e)
        {
            var handler = MovieSearch;
            if (handler != null) handler(this, e);
        }

        public event EventHandler NavigateWeb;
        public void InvokeOnNavigateWeb(NavigateEventArgs e)
        {
            var handler = NavigateWeb;
            if (handler != null) handler(this, e);
        }

        // public event EventHandler WebsiteRequest;
        public event EventHandler UpdateMovie;

        public ImdbInfo()
        {
            InitializeComponent();
        }

        public void LoadMovie(Movie rowMovie)
        {
            if (rowMovie == null) return;
            //lblImdbId.Text = rowMovie.ImdbId;
            var movie = Controller.Db.Movies.Where(a => a.ImdbId == rowMovie.ImdbId).FirstOrDefault();
            if (movie == null)
            {
                textBoxStoryline.Text = "";
                listKeywords.Items.Clear();

                flowCountries.Controls.Clear();
                //flowDirectors.Controls.Clear();
                //flowFileSystem.Controls.Clear();
                //flowGenres.Controls.Clear();
                flowLanguages.Controls.Clear();
                //flowStars.Controls.Clear();
                flowWriters.Controls.Clear();
                flowActors.Controls.Clear();
            }
            else
            {

                textBoxStoryline.Text = movie.Storyline + "";
                listKeywords.DataSource = Controller.Db.MovieKeywords.Where(a => a.Movie.Id == movie.Id).Select(o => o.Keyword);
                LoadCountries(movie, Controller.Db.MovieCountries.Where(a => a.Movie.Id == movie.Id).Select(o => o.Country).ToList());
                //LoadGenres(Controller.Db.MovieGenres.Where(a => a.Movie.Id == movie.Id).Select(o => o.Genre).ToList());
                LoadLanguages(movie, Controller.Db.MovieLanguages.Where(a => a.Movie.Id == movie.Id).Select(o => o.Language).ToList());
                //LoadPeople(Controller.Db.Directors.Where(a => a.Movie.Id == movie.Id).Select(o => o.Person).ToList(), flowDirectors);
                LoadWriters(Controller.Db.Writers.Where(a => a.Movie.Id == movie.Id).Select(o => new SimpleWriter { Id = o.Id, Person = o.Person }).ToList());
                //LoadPeople(Controller.Db.Stars.Where(a => a.Movie.Id == movie.Id).Select(o => o.Person).ToList(), flowStars);
                //LoadFileSystem(Controller.Db.MovieFilesystems.Where(a => a.Movie.Id == movie.Id).ToList());
                LoadActors(movie, Controller.Db.Actors.Where(a => a.Movie.Id == movie.Id).OrderBy(o => o.Person.Name).Select(o => new SimpleActor { Id = o.Id, Person = o.Person, CharacterId = o.CharacterId, CharacterName = o.CharacterName, Birthday = o.Person.Birthday }));
            }
        }

        private void LoadLanguages(Movie movie, IEnumerable<Language> list)
        {
            try
            {
                flowLanguages.Controls.Clear();
                if (list == null) return;
                foreach (var item in list)
                {
                    var linkLabel = new LinkLabel { Text = item.Name, AutoSize = true, Tag = new SimpleKey { MovieId = movie.Id, ItemId = item.Id } };
                    linkLabel.Click += (sender, obj) =>
                    {
                        try
                        {
                            var id = (SimpleKey)(linkLabel.Tag);
                            var me = (MouseEventArgs)obj;
                            if (me.Button == MouseButtons.Middle || (Control.ModifierKeys == Keys.Control && me.Button == MouseButtons.Left))
                            {
                                InvokeOnNavigateWeb(new NavigateEventArgs("http://www.imdb.com/language/" + Controller.Db.Languages.Where(o => o.Id == id.ItemId).Select(o => o.Code).FirstOrDefault()));
                            }
                            else if (me.Button == MouseButtons.Left)
                            {
                                InvokeOnMovieSearchCriteriaClick(new CriteriaSearchEventArgs(typeof(MovieLanguage), Controller.Db.MovieLanguages.Where(o => o.Language.Id == id.ItemId).Select(o => o.Movie).ToList()));
                            }
                        }
                        catch (Exception exp)
                        {
                            InvokeOnDebugText(exp);
                        }
                    };
                    linkLabel.ContextMenuStrip = deleteLanguagesMenu;
                    flowLanguages.Controls.Add(linkLabel);
                }
            }
            catch
            {
            }
        }

        private void LoadCountries(Movie movie, IEnumerable<Country> list)
        {
            try
            {
                flowCountries.Controls.Clear();
                if (list == null) return;
                foreach (var item in list)
                {
                    var linkLabel = new LinkLabel { Text = item.Name, AutoSize = true, Tag = new SimpleKey { MovieId = movie.Id, ItemId = item.Id } };
                    linkLabel.Click += (sender, obj) =>
                    {
                        try
                        {
                            SimpleKey id = (SimpleKey)(linkLabel.Tag);
                            var me = (MouseEventArgs)obj;

                            if (me.Button == MouseButtons.Middle || (Control.ModifierKeys == Keys.Control && me.Button == MouseButtons.Left))
                            {
                                InvokeOnNavigateWeb(new NavigateEventArgs("http://www.imdb.com/country/" + Controller.Db.Countries.Where(o => o.Id == id.ItemId).Select(o => o.Code).FirstOrDefault()));
                            }
                            else if (me.Button == MouseButtons.Left)
                            {
                                InvokeOnMovieSearchCriteriaClick(new CriteriaSearchEventArgs(typeof(MovieCountry), Controller.Db.MovieCountries.Where(o => o.Country.Id == id.ItemId).Select(o => o.Movie).ToList()));
                            }
                        }
                        catch (Exception exp)
                        {
                            InvokeOnDebugText(exp);
                        }
                    };
                    linkLabel.ContextMenuStrip = deleteCountriesMenu;
                    flowCountries.Controls.Add(linkLabel);
                }
            }
            catch
            {
            }
        }

        private void LoadWriters(IEnumerable<SimpleWriter> list)
        {
            try
            {
                flowWriters.Controls.Clear();
                if (list == null) return;
                foreach (var item in list)
                {
                    var linkLabel = new LinkLabel { Text = item.Person.Name, AutoSize = true, Tag = item };
                    linkLabel.Click += (sender, obj) =>
                    {
                        try
                        {
                            var id = (SimpleWriter)linkLabel.Tag;
                            var me = (MouseEventArgs)obj;
                            if (me.Button == MouseButtons.Middle || (Control.ModifierKeys == Keys.Control && me.Button == MouseButtons.Left))
                            {
                                InvokeOnNavigateWeb(new NavigateEventArgs("http://www.imdb.com/name/" + Controller.Db.People.Where(o => o.Id == id.Person.Id).Select(o => o.ImdbId).FirstOrDefault()));
                            }
                            else if (me.Button == MouseButtons.Left)
                            {
                                InvokeOnMovieSearchCriteriaClick(new CriteriaSearchEventArgs(typeof(Writer), Controller.Db.Writers.Where(o => o.Person.Id == id.Person.Id).Select(o => o.Movie).ToList()));
                            }
                        }
                        catch (Exception exp)
                        {
                            InvokeOnDebugText(exp);
                        }
                    };
                    linkLabel.ContextMenuStrip = deleteWritersMenu;
                    flowWriters.Controls.Add(linkLabel);
                }
            }
            catch
            {
            }
        }

        private void LoadActors(Movie movie, IEnumerable<SimpleActor> list)
        {
            try
            {
                flowActors.Controls.Clear();
                if (list == null) return;
                foreach (var item in list)
                {
                    if (item.Person != null)
                    {
                        string age = item.Person.AgeAt(movie.Year);
                        age = age == "" ? age : " (" + age + ")";
                        var linkLabel = new LinkLabel { Text = item.Person.Name.LimitWithElipses(16) + age, AutoSize = true, Tag = item };
                        if (!string.IsNullOrEmpty(item.CharacterName))
                        {
                            linkLabel.Text += " (" + item.CharacterName.LimitWithElipses(16) + ")";
                        }
                        linkLabel.Click += (sender, obj) =>
                                               {
                                                   try
                                                   {
                                                       var actor = (SimpleActor)linkLabel.Tag;
                                                       var me = (MouseEventArgs)obj;
                                                       if (me.Button == MouseButtons.Middle ||
                                                           (Control.ModifierKeys == Keys.Control &&
                                                            me.Button == MouseButtons.Left))
                                                       {
                                                           InvokeOnNavigateWeb(
                                                               new NavigateEventArgs("http://www.imdb.com/name/" +
                                                                                     Controller.Db.Actors.Where(o => o.Id == actor.Id)
                                                                                         .Select(o => o.Person.ImdbId)
                                                                                         .FirstOrDefault()));
                                                       }
                                                       else if (me.Button == MouseButtons.Left)
                                                       {
                                                           InvokeOnMovieSearchCriteriaClick(
                                                               new CriteriaSearchEventArgs(typeof(Actor),
                                                                                           Controller.Db.Actors
                                                                                                .Where(o => o.Person.Id == actor.Person.Id)
                                                                                                .Select(o => o.Movie).ToList()));
                                                       }
                                                   }
                                                   catch (Exception exp)
                                                   {
                                                       InvokeOnDebugText(exp);
                                                   }
                                               };
                        linkLabel.ContextMenuStrip = deleteActorsMenu;
                        flowActors.Controls.Add(linkLabel);
                    }
                    else
                    {
                        InvokeOnDebugText(string.Format("Person is Null though Actor [{0}({1}] is present.", item.CharacterName, item.CharacterId));
                    }
                }
            }
            catch
            {
            }
        }

        private void ListKeywordsFormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e)
        {
            var w = (Keyword)e.Model;
            e.Item.ForeColor = ComponentUtility.HardnessForeground[w.Rated];
            e.Item.BackColor = ComponentUtility.HardnessBackground[w.Rated];
            e.Item.Font = w.Rated > 0 ? new Font(listKeywords.Font, FontStyle.Bold) : new Font(listKeywords.Font, FontStyle.Regular);

        }

        private void ListKeywordsDoubleClick(object sender, EventArgs e)
        {
            try
            {
                var list = (from Keyword keyword in listKeywords.CheckedObjects select keyword.Id).ToList();
                if (list.Count == 0) return;
                var movies = Controller.Db.MovieKeywords.WhereIn(o => o.Keyword.Id, list).Select(o => o.Movie).ToList().Distinct().ToList();
                InvokeOnMovieSearchCriteriaClick(new CriteriaSearchEventArgs(typeof(MovieKeyword), movies));
            }
            catch (Exception exp)
            {
                InvokeOnDebugText(exp);
            }
        }

        private void SearchTextBoxSearchStarted(object sender, EventArgs e)
        {
            ComponentUtility.TimedFilter(listKeywords, searchTextBox.Text);
        }

        private void SearchTextBoxSearchCancelled(object sender, EventArgs e)
        {
            ComponentUtility.TimedFilter(listKeywords, "");
        }

        private void ListKeywordsSelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                var keyword = listKeywords.SelectedObject as Keyword;
                rsKeywordRating.Rating = keyword != null ? keyword.KeywordRating : 0;
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void RsKeywordRatingRatingValueChanged(object sender, NymphsLib.RatingControl.RatingChangedEventArgs e)
        {
            try
            {
                foreach (Keyword keyword in listKeywords.SelectedObjects)
                {
                    keyword.Rated = (int)e.NewRating;
                }
                Controller.Db.SaveChanges();
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void DeleteToolStripMenuItemClick(object sender, EventArgs e)
        {
            try
            {
                var menu = (ToolStripDropDownItem)sender;
                var strip = (ContextMenuStrip)menu.Owner;
                var owner = strip.SourceControl;

                if (owner != null)
                {
                    var id = ((SimpleActor)owner.Tag);
                    var actor = Controller.Db.Actors.Where(o => o.Id == id.Id).FirstOrDefault();
                    if (actor == null)
                        return;
                    Controller.Db.DeleteObject(actor);
                    Controller.Db.SaveChanges();
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void DeleteWritersMenuItemClick(object sender, EventArgs e)
        {
            try
            {
                var menu = (ToolStripDropDownItem)sender;
                var strip = (ContextMenuStrip)menu.Owner;
                var owner = strip.SourceControl;

                if (owner != null)
                {
                    var id = ((SimpleWriter)owner.Tag);
                    var actor = Controller.Db.Writers.Where(o => o.Id == id.Id).FirstOrDefault();
                    if (actor == null)
                        return;
                    Controller.Db.DeleteObject(actor);
                    Controller.Db.SaveChanges();
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void updateToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            try
            {
                var menu = (ToolStripDropDownItem)sender;
                var strip = (ContextMenuStrip)menu.Owner;
                var owner = strip.SourceControl;

                if (owner != null)
                {
                    var id = ((SimpleActor)owner.Tag);
                    var actor = Controller.Db.Actors.Where(o => o.Id == id.Id).Select(o => o.Person).ToList();
                    Controller.UpdatePersonInformation(actor);
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void deleteLanguagesStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                var menu = (ToolStripDropDownItem)sender;
                var strip = (ContextMenuStrip)menu.Owner;
                var owner = strip.SourceControl;

                if (owner != null)
                {
                    var id = ((SimpleKey)owner.Tag);
                    var dbEntry = Controller.Db.MovieLanguages.Where(o => o.Movie.Id == id.MovieId && o.Language.Id == id.ItemId).FirstOrDefault();
                    if (dbEntry == null)
                        return;
                    Controller.Db.DeleteObject(dbEntry);
                    Controller.Db.SaveChanges();
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }

        private void deleteCountriesMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                var menu = (ToolStripDropDownItem)sender;
                var strip = (ContextMenuStrip)menu.Owner;
                var owner = strip.SourceControl;

                if (owner != null)
                {
                    var id = ((SimpleKey)owner.Tag);
                    var dbEntry = Controller.Db.MovieCountries.Where(o => o.Movie.Id == id.MovieId && o.Country.Id == id.ItemId).FirstOrDefault();
                    if (dbEntry == null)
                        return;
                    Controller.Db.DeleteObject(dbEntry);
                    Controller.Db.SaveChanges();
                }
            }
            catch (Exception exception)
            {
                InvokeOnDebugText(exception);
            }
        }
    }
}
